#include <stdio.h>

#include "msg_queue.h"

//定义消息队列名称
#define QUEQUE_NAME "/mq_queue"

/**
 * 创建消息队列
 * 功能：创建并初始化一个POSIX消息队列，用于进程内或进程间通信
 * 消息队列特性：
 * - 持久化命名队列，系统范围内唯一标识
 * - 具有固定的消息大小和最大消息数量限制
 * - 线程安全的同步机制
 * @return mqd_t 消息队列描述符，创建失败返回-1
 */
mqd_t msg_queue_create(void)
{
    //创建消息队列
    mqd_t mqd = -1;//初始化消息队列描述符为无效
    struct mq_attr attr;//消息队列属性结构体

    //设置消息队列属性
    attr.mq_flags = 0;  //消息队列标志，0表示组赛模式
    attr.mq_maxmsg = 10;    //消息队列最大消息数量
    attr.mq_msgsize = 256;  //每条消息的最大字节数
    attr.mq_curmsgs = 0;    //当前列中的消息数量，创建时为0

    // 创建或打开消息队列
    // 参数说明：
    // QUEQUE_NAME: 队列名称，以'/'开头
    // O_CREAT | O_RDWR: 创建队列(如果不存在)并以读写方式打开
    // 0666: 权限设置，所有者、组和其他用户都有读写权限
    // &attr: 指向队列属性结构体的指针
    mqd = mq_open(QUEQUE_NAME, O_CREAT | O_RDWR, 0666, &attr);

    //打印：显示文件名、函数名、行号喝消息队列描述符
    printf("%s| %s |%d: mqd = %d\n",__FILE__, __func__, __LINE__, mqd);

    return mqd;
}

/**
 * 释放消息队列资源
 * 功能：关闭并删除消息队列，释放相关系统资源
 * 清理步骤：
 * 1. 关闭消息队列描述符
 * 2. 从系统中删除消息队列
 * 3. 将描述符重置为无效值
 * @param mqd 要释放的消息队列描述符
 */
void msg_queue_final(mqd_t mqd)
{
    //检查消息队列描述符是否有效
    if (-1 != mqd)
        mq_close(mqd);//关闭消息队列，释放描述符资源

    //从系统中删除消息队列名称，使其不再可用
    mq_unlink(QUEQUE_NAME);

    mqd = -1;//将描述符重置为无效值（注意：这只是局部遍历的修改，不会影响调用者）
}

/**
 * 发送消息到消息队列
 * 功能：将指定数据作为消息发送到消息队列中
 * 注意事项：
 * - 消息长度不能超过创建队列时设定的最大消息大小
 * - 如果队列已满，根据标志位决定是否阻塞等待
 * @param mqd     消息队列描述符
 * @param msg     指向要发送消息内容的指针
 * @param msg_len 要发送消息的字节长度
 * @return int    成功发送的字节数，失败返回-1
 */
int send_message(mqd_t mqd, void *msg, int msg_len)
{
    int byte_send = -1;//初始化发送字节数为无效值

    // 发送消息到消息队列
    // 参数说明：
    // mqd: 消息队列描述符
    // (char *)msg: 指向消息内容的指针，需转换为char*
    // msg_len: 消息长度（字节数）
    // 0: 消息优先级，数值越大优先级越高，这里设为最低优先级
    byte_send = mq_send(mqd, (char *)msg, msg_len, 0);
    
    return byte_send;//返回实际发送的字节数或-1（失败）
}